﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace FriendlyFire.UserControls
{
    public partial class Search : UserControl
    {
        private Video video;
        private TabControl tabs;
        private Helper myHelper;
        private SearchFor currentSearchInfo;


        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="v">Reference to video user control</param>
        /// <param name="t">Reference to tab control</param>
        /// <param name="ffHelper">Reference to friendly fire helpe</param>
        public Search(ref Video v, ref TabControl t, ref Helper ffHelper)
        {
            InitializeComponent();
            video = v;
            tabs = t;
            myHelper = ffHelper;
            playbox.ValueMember = "Dir";
            playbox.DisplayMember = "Name";
        }

        /// <summary>
        /// Provides focus to the searchbox
        /// </summary>
        public void ActivateSearchBoxField()
        {
            searchBox.Select();
        }

        #region searchBox_keydown
        //TODO review this. the new DB layer may not have this problem.
        /// <summary>
        /// Keydown. Ignore the equals key. Messes up queries.
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void searchBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyValue.Equals(187)) // 187 is the = / equals key
            {
                e.SuppressKeyPress = true;
            }
        }
        #endregion

        #region searchBox_textchange
        /// <summary>
        /// Performs the search based on given parameters
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void searchBox_TextChanged(object sender, EventArgs e)
        {
            try
            {
                if (searchBox.Text == "") { searchResults.DataSource = null; }
                else
                {
                    #region Populate the SearchFor structure
                    SearchFor sf = new SearchFor(searchBox.Text, txtCustom.Text);
                    if (chkAnything.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Anything); };
                    if (chkArchives.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Archives); };
                    if (chkAudio.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Audio); };
                    if (chkCustom.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Custom); };
                    if (chkDocuments.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Documents); };
                    if (chkVideo.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Video); };
                    #endregion

                    /*if (chkFriends.Checked)   //TODO update to new system
                    {
                        MemoryStream ms = new MemoryStream();
                        BinaryFormatter bf = new BinaryFormatter();
                        bf.Serialize(ms, sf);
                        byte[] bytesToSend = ms.GetBuffer();
                        this.CurrentSearchInfo = sf;    // remember what we just searched for
                        // so the netcode knows what to append, and
                        // what to ignore.
                        foreach (Client c in myParent.Clients)  // send request to all online friends
                        {
                            if (c.IsConnected)
                            {
                                c.SendData(bytesToSend, 602); // Sending the SearchFor info class
                            }
                        }   //results from friends will come in behind the scenes
                        //and be merged as they arrive.
                    }*/

                    if (chkMyMachine.Checked)
                    {
                        DataTable dt = SearchIndex(sf).Tables[0];
                        dt.Columns.Add("owner", Type.GetType("System.String"), "'localhost'");
                        searchResults.DataSource = dt;
                        searchResults.Columns[0].Visible = false;
                        searchResults.Columns[2].Visible = false;
                        searchResults.Columns[3].Visible = false;
                        searchResults.Columns[4].Visible = false;   //metadataID
                        searchResults.Columns[5].Visible = false;   // owner
                        searchResults.Columns[1].HeaderText = "File Name";
                        searchResults.Columns[1].Width = searchResults.Width - 22;
                    }


                }
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
                MessageBox.Show("An error has occured while executing your query.");
            }
        }
        #endregion

        //private delegate void UpdateDSDelegate(DataSet ds);
        //public void SetSearchResultsDataSource(DataSet ds)
        //{
        //    if (searchResults.InvokeRequired)
        //    {
        //        searchResults.Invoke(new UpdateDSDelegate(SetSearchResultsDataSource), ds);
        //    }
        //    else
        //    {
        //        searchResults.DataSource = ds.Tables[0];
        //    }
        //    // use the first table in the DS

        //}

        private delegate void UpdateDSDelegate(DataSet dsMore);
        public void MergeResults(DataSet dsMore)
        {
            if (searchResults.InvokeRequired)
            {
                searchResults.Invoke(new UpdateDSDelegate(MergeResults), dsMore);
            }
            else
            {
                //DataTable currentDT = (DataTable)searchResults.DataSource;
                //currentDT.Merge(dsMore.Tables[0]);
                //searchResults.DataSource = currentDT;
                searchResults.DataSource = null;
                //if (currentDT != null)
                //{
                //    foreach (DataRow dr in dsMore.Tables[0].Rows)
                //    {
                //        currentDT.ImportRow(dr);
                //    }
                searchResults.DataSource = dsMore.Tables[0];
                    //searchResults.Columns[0].Visible = false;
                    //searchResults.Columns[2].Visible = false;
                    //searchResults.Columns[3].Visible = false;
                    //searchResults.Columns[4].Visible = false;   //metadataID
                    //searchResults.Columns[5].Visible = false;   // owner
                    searchResults.Columns[1].HeaderText = "File Name";
                    searchResults.Columns[1].Width = searchResults.Width - 22;
                //}
                //else
                //{
                //    //TODO might need a theadsafe callback here.
                //    searchResults.DataSource = dsMore.Tables[0];
                //    //searchResults.Columns[0].Visible = false;
                //    //searchResults.Columns[2].Visible = false;
                //    //searchResults.Columns[3].Visible = false;
                //    //searchResults.Columns[4].Visible = false;   //metadataID
                //    //searchResults.Columns[5].Visible = false;   // owner
                //    searchResults.Columns[1].HeaderText = "File Name";
                //    searchResults.Columns[1].Width = searchResults.Width - 22;
                //    searchResults.Refresh();
                //}
            }
        }

        #region SuperIndexSearch
        /// <summary>
        /// Super Search FUCK YEAH!
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        public DataSet SearchIndex(SearchFor info)
        {
            #region old
            /*SubSonic.Query q;
            if (info.LookAt.Contains(SearchForTypes.FileType.Anything) || info.LookAt.Count.Equals(0)) // overrides all others
            {
                q = new SubSonic.Query("file").WHERE("name LIKE %" + info.Query + "%");
                return q.ExecuteDataSet();
            }

            string[] extArch = { ".zip", ".7z", ".rar", ".tar", ".gz", ".bz2", ".tgz" };
            string[] extAud = { ".mp3", ".wma", ".wav", ".ogg", ".aac", ".flac" };
            string[] extDocs = { ".doc", ".txt", ".rtf", ".docx", ".xls", ".odt" };
            string[] extVid = { ".divx", ".avi", ".wmv", ".mov", ".flv", ".mpg", ".mkv" };


            q = new SubSonic.Query("file").WHERE("name LIKE %" + info.Query + "%");
            bool hasAND = false;
            bool zeroStart = true;
            if (info.LookAt.Contains(SearchForTypes.FileType.Archives))
            {
                q = q.AND("extension = " + extArch[0]);
                hasAND = true;
                for (int i = 1; i < extArch.Length; i++)
                {
                    q = q.OR("extension = " + extArch[i]);
                    q = q.AND("name LIKE %" + info.Query + "%");
                }

            }
            if (info.LookAt.Contains(SearchForTypes.FileType.Audio))
            {
                zeroStart = true;
                if (!hasAND)
                {
                    q = q.AND("extension = " + extAud[0]);
                    hasAND = true;
                    zeroStart = false;
                }
                for (int i = ((zeroStart) ? 0 : 1); i < extAud.Length; i++)
                {
                    q = q.OR("extension = " + extAud[i]);
                    q = q.AND("name LIKE %" + info.Query + "%");

                }
            }
            if (info.LookAt.Contains(SearchForTypes.FileType.Documents))
            {
                zeroStart = true;
                if (!hasAND)
                {
                    q = q.AND("extension = " + extDocs[0]);
                    hasAND = true;
                    zeroStart = false;
                }
                for (int i = ((zeroStart) ? 0 : 1); i < extDocs.Length; i++)
                {
                    q = q.OR("extension = " + extDocs[i]);
                    q = q.AND("name LIKE %" + info.Query + "%");
                }
            }
            if (info.LookAt.Contains(SearchForTypes.FileType.Video))
            {
                zeroStart = true;
                if (!hasAND)
                {
                    q = q.AND("extension = " + extVid[0]);
                    hasAND = true;
                    zeroStart = false;
                }
                for (int i = ((zeroStart) ? 0 : 1); i < extVid.Length; i++)
                {
                    q = q.OR("extension = " + extVid[i]);
                    q = q.AND("name LIKE %" + info.Query + "%");
                }
            }
            if (info.LookAt.Contains(SearchForTypes.FileType.Custom))
            {
                if (!hasAND)
                {
                    q = q.AND("extension = " + info.CustomType);
                    hasAND = true;
                }
                else
                {
                    q = q.OR("extension = " + info.CustomType);
                    q = q.AND("name LIKE %" + info.Query + "%");
                }
            }*/
            #endregion
            return myHelper.DBHelper.PerformSearchOnLocalIndex(info);
        }
        #endregion

        #region GetSelectedRows
        /// <summary>
        /// Returns the collection of selected rows
        /// from search grid. If nothing has been searched
        /// for, then this is null.
        /// </summary>
        /// <returns>Searchresult's selectedrows</returns>
        public DataGridViewSelectedRowCollection GetSelectedRows()
        {
            return searchResults.SelectedRows;
        }
        #endregion

        #region Paint Overrides
        /// <summary>
        /// Paint override. Draws a veritcal gradient for the background
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void Search_Paint(object sender, PaintEventArgs e)
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            myHelper.DrawDefaultBackGroundGradient(e.Graphics, ClientRectangle);
        }

        private void groupBox2_Paint(object sender, PaintEventArgs e)
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }

        private void groupBox3_Paint(object sender, PaintEventArgs e)
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
        #endregion

        /// <summary>
        /// Derives a file link from the selected searchresults row
        /// </summary>
        /// <returns>String of file location</returns>
        public string getLink()
        {
            if (searchResults.SelectedRows.Count > 0)
            {
                return searchResults.SelectedRows[0].Cells[3].Value.ToString() + "\\" + searchResults.SelectedRows[0].Cells[1].Value.ToString();

            }
            return "";
        }

        #region Grid Double Click
        /// <summary>
        /// Event fired when a result is double clicked, plays a file of the selectedrow
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void searchResults_DoubleClick(object sender, EventArgs e)
        {
            if (searchResults.SelectedRows.Count > 0)
            {
                video.vactx.playlist.clear();
                video.vactx.Visible = true;
                int id = video.vactx.playlist.add(searchResults.SelectedRows[0].Cells[3].Value.ToString() +
                                "\\" + searchResults.SelectedRows[0].Cells[1].Value.ToString(),
                                searchResults.SelectedRows[0].Cells[1].Value.ToString(), null);
                video.vactx.playlist.playItem(id);
                tabs.SelectedTab = tabs.TabPages[4];
            }
        }
        #endregion

        #region Checkbox Checking Behavior
        /// <summary>
        /// Event fired when the "anything" checkbox is selected, deselects all other checkboxes
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void chkAnything_Click(object sender, EventArgs e)
        {
            if (chkAnything.Checked)
            {
                chkArchives.Checked = false;
                chkAudio.Checked = false;
                chkCustom.Checked = false;
                chkDocuments.Checked = false;
                chkVideo.Checked = false;
            }

            searchBox_TextChanged(null, null);
        }

        /// <summary>
        /// Fires if anything besides the "anything" checkbox is checked, deselects the "anything" checkbox
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void AnythingButAnythingChecked(object sender, EventArgs e)
        {
            chkAnything.Checked = false;
            searchBox_TextChanged(null, null);
        }
        #endregion

        /// <summary>
        /// This event makes sure the search user control always properly draws the correct ratios even if the form is resized
        /// </summary>
        /// <param name="sender">Object sending the event</param>
        /// <param name="e">any event arguments that need to be passed</param>
        private void Search_Resize(object sender, EventArgs e)
        {
            //resize panels to accomadate window height
            searchResults.Height = this.Size.Height - 163;
            playbox.Height = this.Size.Height - 226;
        }
        #region Accessors
        public SearchFor CurrentSearchInfo
        {
            get { return currentSearchInfo; }
            set { currentSearchInfo = value; }
        }
        #endregion

        private void btnSearchFriends_Click(object sender, EventArgs e)
        {/*
            if (searchBox.Text == "") { searchResults.DataSource = null; }
            {
                #region Populate the SearchFor structure
                SearchFor sf = new SearchFor(searchBox.Text, txtCustom.Text);
                if (chkAnything.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Anything); };
                if (chkArchives.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Archives); };
                if (chkAudio.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Audio); };
                if (chkCustom.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Custom); };
                if (chkDocuments.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Documents); };
                if (chkVideo.Checked) { sf.LookAt.Add(SearchForTypes.FileType.Video); };
                #endregion
                MemoryStream ms = new MemoryStream();
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(ms, sf);
                byte[] bytesToSend = ms.GetBuffer();
                this.CurrentSearchInfo = sf;    // remember what we just searched for
                // so the netcode knows what to append, and
                // what to ignore.
                foreach (Client c in myParent.Clients)  // send request to all online friends
                {
                    if (c.IsConnected)
                    {
                        c.SendData(bytesToSend, 602); // Sending the SearchFor info class
                    }
                }
            }*/
        }

        private void searchResults_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
        {


        }

        private void searchResults_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (searchResults.HitTest(e.X, e.Y).RowIndex != -1)
                {
                    for (int i = 0; i < searchResults.SelectedRows.Count; )
                    {
                        searchResults.SelectedRows[i].Selected = false;
                    }
                    searchResults.Rows[searchResults.HitTest(e.Location.X, e.Location.Y).RowIndex].Selected = true;
                    if (!searchResults.SelectedRows[0].Cells[5].Value.ToString().Equals("localhost"))
                    {
                        remoteMenu.Popup(MousePosition);
                    }
                    else
                    {
                        contextMenu.Popup(MousePosition);
                    }
                }
            }
        }

        //private void Play_Click(object sender, EventArgs e)   //where did this come from?
        //{
        //    if (searchResults.SelectedRows.Count > 0)
        //    {
        //        string[] extAV = { ".divx", ".avi", ".wmv", ".mov", ".flv", ".mpg", ".mkv", ".mp3", ".wma", ".wav", ".ogg", ".aac", ".flac" };
        //        if (extAV.Contains<string>(searchResults.SelectedRows[0].Cells[2].Value.ToString()))
        //        {
        //            video.listFlag = false;
        //            video.checkPaused = false;
        //            tabs.TabPages[4].BackColor = Color.Black;   //prevents oldbg from tearing thru before resize.
        //            tabs.TabPages[4].Refresh();
        //            video.PlayFile(searchResults.SelectedRows[0].Cells[3].Value.ToString() +
        //                            "\\" +
        //                            searchResults.SelectedRows[0].Cells[1].Value.ToString());
        //            tabs.SelectedTab = tabs.TabPages[4];
        //        }
        //    }
        //}

        private void searchResults_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

        }

        private void Preview_Click(object sender, EventArgs e)
        {
            //myParent.imagesrecieved = 0;
            //myParent.currentimage = 0;
            //for (int i = 0; i < 5; i++)
            //{
            //    myParent.previewimages[i] = new System.Drawing.Bitmap("bp.bmp");
            //}
            //TODO: parse and ask for shit

        }

        private void Enque_Click(object sender, EventArgs e)
        {
            string[] extAV = { ".divx", ".avi", ".wmv", ".mov", ".flv", ".mpg", ".mkv", ".mp3", ".wma", ".wav", ".ogg", ".aac", ".flac" };
            if (extAV.Contains<string>(searchResults.SelectedRows[0].Cells[2].Value.ToString()))
            {
                playbox.Items.Add(new QueueItem(searchResults.SelectedRows[0].Cells[3].Value.ToString(),
                                            searchResults.SelectedRows[0].Cells[1].Value.ToString(),
                                            (long)searchResults.SelectedRows[0].Cells[0].Value));
            }
        }

        private void playbox_DoubleClick(object sender, EventArgs e)
        {
            video.vactx.playlist.clear();
            video.vactx.Visible = true;
            int id = video.vactx.playlist.add(((QueueItem)playbox.Items[playbox.SelectedIndex]).Dir +
                            "\\" + ((QueueItem)playbox.Items[playbox.SelectedIndex]).Name,
                            ((QueueItem)playbox.Items[playbox.SelectedIndex]).Name, null);
            video.vactx.playlist.playItem(id);
            tabs.SelectedTab = tabs.TabPages[4];
        }


        private void playbox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete && playbox.SelectedIndex != -1)
            {
                playbox.Items.RemoveAt(playbox.SelectedIndex);
            }
            if (e.KeyCode == Keys.Enter)
            {
                video.vactx.playlist.clear();
                video.vactx.Visible = true;
                int id = video.vactx.playlist.add(((QueueItem)playbox.Items[playbox.SelectedIndex]).Dir +
                                "\\" + ((QueueItem)playbox.Items[playbox.SelectedIndex]).Name,
                                ((QueueItem)playbox.Items[playbox.SelectedIndex]).Name, null);
                video.vactx.playlist.playItem(id);
                tabs.SelectedTab = tabs.TabPages[4];
            }
        }

        private void saveListBtn_Click(object sender, EventArgs e)
        {
            if (playbox.Items.Count.Equals(0))
            {
                MessageBox.Show("The playlist is empty, there's nothing to save.", "Empty Playlist", MessageBoxButtons.OK);
            }
            else
            {
                try
                {
                    myHelper.DBHelper.SavePlayList((listName.Text.Equals("") ? "Unnamed List" : listName.Text.Trim()), playbox.Items);
                }
                catch (Exception err)
                {
                    // error while saving 
                }
            }
        }

        private void playlistMenu_OptionSelected(object sender, CircularMenu.MenuEventArgs args)
        {

        }

        private void playbox_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (playbox.IndexFromPoint(e.X, e.Y) != -1)
                {
                    playbox.SelectedIndex = playbox.IndexFromPoint(e.X, e.Y);
                    playlistMenu.Popup(MousePosition);
                }
            }
        }

        private void Remove_Click(object sender, EventArgs e)
        {
            if (playbox.SelectedIndex != -1)
            {
                playbox.Items.RemoveAt(playbox.SelectedIndex);
            }
        }

        private void playPlay_Click(object sender, EventArgs e)
        {
            video.vactx.playlist.clear();
            video.vactx.Visible = true;
            int id = video.vactx.playlist.add(((QueueItem)playbox.Items[playbox.SelectedIndex]).Dir +
                            "\\" + ((QueueItem)playbox.Items[playbox.SelectedIndex]).Name,
                            ((QueueItem)playbox.Items[playbox.SelectedIndex]).Name, null);
            video.vactx.playlist.playItem(id);
            tabs.SelectedTab = tabs.TabPages[4];
        }

        private void Movedown_Click(object sender, EventArgs e)
        {
            if (playbox.Items.Count - 1 != playbox.SelectedIndex )
            {
                playbox.Items.Insert(playbox.SelectedIndex + 2, playbox.Items[playbox.SelectedIndex]);
                playbox.Items.RemoveAt(playbox.SelectedIndex);
            }
        }

        private void MoveUp_Click(object sender, EventArgs e)
        {
            if (0 != playbox.SelectedIndex)
            {
                playbox.Items.Insert(playbox.SelectedIndex - 1, playbox.Items[playbox.SelectedIndex]);
                playbox.Items.RemoveAt(playbox.SelectedIndex);
            }
        }

        //TODO needs new network layer. and different stream mode
        //TODO start VLC in invisible mode via command line.
        private void Stream_Click(object sender, EventArgs e)
        {/*
            for (int i = 0; i < myParent.Clients.Count; i++)
            {
                if (searchResults.SelectedRows[0].Cells[5].Value.ToString() == myParent.Clients[i].BsPublicKey)
                {
                    myParent.Clients[i].SendData(Encoding.ASCII.GetBytes(searchResults.SelectedRows[0].Cells[0].Value.ToString()), 231);
                    break;
                }
            }*/
        }

        //TODO needs new network layer
        private void Download_Click(object sender, EventArgs e)
        {/*
            if (searchResults.SelectedRows[0].Cells[5].ToString() != "localhost")
            {
                foreach (Client c in myParent.Clients)
                {
                    if (c.BsPublicKey.Equals(searchResults.SelectedRows[0].Cells[5].Value.ToString()))
                    {
                        string fileRequested = searchResults.SelectedRows[0].Cells[3].Value.ToString() + "\\" + searchResults.SelectedRows[0].Cells[1].Value.ToString();
                        c.SendData(ASCIIEncoding.ASCII.GetBytes(fileRequested), 900);
                    }
                }
            }*/
        }

        private void chkFriends_Click(object sender, EventArgs e)
        {
            chkFriends.Checked = true;
            chkMyMachine.Checked = false;
        }

        private void chkMyMachine_Click(object sender, EventArgs e)
        {
            chkFriends.Checked = false;
            chkMyMachine.Checked = true;
        }

        private void listName_MouseUp(object sender, MouseEventArgs e)
        {
            if (listName.Text.Equals("List Name"))
            {
                listName.SelectAll();
            }
        }
    }
}
